# -*- coding: utf-8 -*-
# time: 2023/8/1 14:36
# author: hanson
# !/usr/bin/env python
# coding=utf-8
"""
mqttClient :

"""
import webbrowser, sys, ctypes
import tkinter as tk
from tkinter import messagebox, ttk
import paho.mqtt.client as mqtt

import childWin
import dataApi


def is_admin():
    try:
        return ctypes.windll.shell32.IsUserAnAdmin()
    except:
        return False


class RootFrom:
    # Define global mqtt connection state
    isConnect = 0

    def __init__(self):
        # Function data selection
        global cves

        banner = "数据日志 \n"
        cves = ("md5", "urlEncode", "urlDecode", "bk加密", "bk解密", "json格式化")
        self.root = tk.Tk()
        self.root.title("mqttClient+工具类")
        self.root.geometry("1024x439")
        self.root.resizable(0, 0)

        # 泄露扫描
        tk.Label(self.root, text="工具类").place(x=190, y=5)
        tk.Label(self.root, text=" MQIP").place(x=100, y=30)
        tk.Label(self.root, text="  端口").place(x=100, y=60)
        tk.Label(self.root, text="clientId").place(x=100, y=90)
        tk.Label(self.root, text="  账号").place(x=90, y=120)
        tk.Label(self.root, text="  密码").place(x=90, y=150)
        tk.Label(self.root, text="操作").place(x=100, y=180)
        # tk.Label(self.root, text="  md5").place(x=90, y=214)
        self.box_se = ttk.Combobox(self.root, width=10)
        self.box_se['value'] = cves
        self.box_se.current(0)
        self.box_se.place(x=20, y=214)
        # 漏洞利用
        # tk.Label(self.root, text="加密数据").place(x=180, y=235)
        # tk.Label(self.root, text="解密数据").place(x=85, y=260)
        # tk.Label(self.root, text="CVEs").place(x=100, y=290)
        # tk.Label(self.root, text="urlEncode").place(x=60, y=320)
        # tk.Label(self.root, text="md5").place(x=60, y=350)

        # 泄露扫描控件
        self.url = tk.Entry(self.root, textvariable=tk.StringVar(value=''))
        self.url.place(x=150, y=30)

        self.port = tk.Entry(self.root, textvariable=tk.IntVar(value=''))
        self.port.place(x=150, y=60)

        self.cllientId = tk.Entry(self.root)  # state='disable'
        self.cllientId.place(x=150, y=90)

        self.userName = tk.Entry(self.root, textvariable=tk.StringVar(value=''))
        self.userName.place(x=150, y=120)

        self.pwd = tk.Entry(self.root, textvariable="", show="*")
        self.pwd.place(x=150, y=150)
        # 连接
        self.btn = tk.Button(self.root, text='连 接', command=self.mqttCon)  # 把按钮和函数dayin绑定，点击按钮时，执行此函数
        self.btn.place(x=150, y=180)
        # 断开
        self.btn = tk.Button(self.root, text='断 开', command=self.disCon)  # 把按钮和函数dayin绑定，点击按钮时，执行此函数
        self.btn.place(x=250, y=180)
        # self.info_dict = tk.Entry(self.root, state='disable')
        # self.info_dict.place(x=150, y=180)
        # build_text
        self.build_text = tk.Entry(self.root, textvariable=tk.StringVar(value=''))
        self.build_text.place(x=150, y=214)
        # 控件
        # self.encode_text = tk.Entry(self.root, textvariable=tk.StringVar(value='urlEncode'))
        # self.encode_text.place(x=150, y=260)
        # self.md5_e.insert(0, "whoami")

        # self.rank = tk.Entry(self.root)
        # self.rank.place(x=150, y=320)
        # self.ranks = tk.Entry(self.root, state='disable')
        # self.ranks.place(x=150, y=350)
        """
        tk.Button(self.root, text="浏览", command=self.Openfiledir1).place(x=300, y=55)
        tk.Button(self.root, text="浏览", command=self.Openfiledir2).place(x=300, y=145)
        tk.Button(self.root, text="浏览", command=self.Openfiledir3).place(x=300, y=175)
        tk.Button(self.root, text="浏览", command=self.Openfiledir5).place(x=300, y=205)
        tk.Button(self.root, text="浏览", command=self.Openfiledir4).place(x=300, y=345)
        # 执行按钮
        tk.Button(self.root, text="xx扫描", command=self.scan).place(x=70, y=390)
        tk.Button(self.root, text="xxx", command=self.vule).place(x=140, y=390)
        tk.Button(self.root, text="下载", command=self.dumpinfo).place(x=210, y=390)
        tk.Button(self.root, text="全部清除", command=self.clear).place(x=280, y=390)
        tk.Button(self.root, text="执行", command=self.CVE_2022_22965_Exec).place(x=300, y=255)
        tk.Button(self.root, text="识别", command=self.nmap_scan).place(x=300, y=315) #E8D1A5 
        """
        tk.Button(self.root, text="提交", command=self.build_submit).place(x=300, y=205)
        # tk.Button(self.root, text="浏览", command=self.build_submit).place(x=300, y=345)

        # 反馈框 分2个
        self.vbar = ttk.Scrollbar(self.root)
        self.info_text = tk.Text(self.root, width=95, height=20, yscrollcommand=self.vbar.set)
        self.info_text.insert(tk.INSERT, banner)
        self.info_text.place(x=350, y=0)
        self.vbar.config(command=self.info_text.yview)
        self.vbar.pack(side=tk.RIGHT, fill="y")

        # self.vbar2 = ttk.Scrollbar(self.root)
        self.input_text = tk.Text(self.root, width=95, height=9)
        # self.input_text.insert(tk.INSERT)
        self.input_text.place(x=350, y=280)
        # send 消息
        self.sbtn = tk.Button(self.root, text='发 送', bg='#7CCD7C', width=12, height=1,
                              command=self.sendMsg)  # 把按钮和函数dayin绑定，点击按钮时，执行此函数
        self.sbtn.place(x=910, y=402)
        # clear 消息
        self.btn_clear = tk.Button(self.root, text='清 空', bg='#7CCD7C', width=12, height=1,
                                   command=self.clearMsg)
        self.btn_clear.place(x=810, y=402)
        # self.vbar2.config(command=self.input_text.yview)
        # self.vbar2.pack(side=tk.RIGHT, fill="y")
        # 日志功能
        self.log_var = tk.StringVar(self.root)
        self.log = ttk.Checkbutton(self.root, text="日志功能", variable=self.log_var, onvalue="启用", offvalue="不启用")
        self.log.place(x=255, y=5)
        # 菜单容器创建
        menu = tk.Menu(self.root)
        # 创建菜单
        menu_kid = tk.Menu(menu, tearoff=0)
        menu.add_cascade(label='菜单', menu=menu_kid)
        menu_kid.add_command(label='swagger_API', command=API_from)
        menu_kid.add_command(label='软件信息', command=self.software_info)
        # menu_kid.add_command(label='Shell信息', command=self.shell_info)
        menu_kid.add_separator()
        menu_kid.add_command(label='退出', command=self.Exit, accelerator='Esc')
        """
        menu_info = tk.Menu(menu, tearoff=0)
        menu.add_cascade(label='清除', menu=menu_info)
        dir_clear = tk.Menu(menu, tearoff=0)
        menu_info.add_cascade(label='路径清除', menu=dir_clear)
        """
        menu_get = tk.Menu(menu, tearoff=0)
        menu.add_cascade(label='更多', menu=menu_get)
        # menu_get.add_command(label='利用姿势', command=self.vule_info)
        # menu_get.add_command(label='FafaViewer', command=self.fofa_viewer)
        #menu_get.add_command(label='Git项目', command=self.git_hub)

        def Menu_Right(event):
            global right
            menu_right.post(event.x_root, event.y_root)

        def Menu_Esc(event=None):
            self.Exit()

        # 右键菜单设置
        menu_right = tk.Menu(self.root, tearoff=False)
        right = self.root
        menu_right.add_command(label='打开IotAPi', command=self.IotAPi, accelerator='Ctrl+a')
        menu_right.add_separator()
        menu_right.add_command(label='打开云平台', command=self.Iot, accelerator='Ctrl+1')
        menu_right.add_separator()
        """
        right_clear = tk.Menu(menu_right, tearoff=0)
        menu_right.add_cascade(label='路径清除', menu=right_clear)
        right_clear.add_command(label='xxx', command=self.clear_dir1)
        right_clear.add_command(label='xx', command=self.clear_dir2)
        right_clear.add_command(label='xx字典', command=self.clear_dir3)
        right_clear.add_command(label='xx下载', command=self.clear_dir5)
        right_clear.add_command(label='xxx', command=self.clear_dir4)
        right_clear.add_command(label='ALL清除', command=self.clear_dirs)
        """
        menu_right.add_separator()
        # menu_right.add_command(label='Shell信息', command=self.shell_info, accelerator='Ctrl+P')
        menu_right.add_separator()
        right_more = tk.Menu(menu_right, tearoff=0)
        menu_right.add_cascade(label='更多', menu=right_more)
        right_more.add_command(label='Git项目')

        self.root.bind("<Escape>", Menu_Esc)
        self.root.bind("<Escape>", Menu_Esc)
        self.root.bind("<Button-3>", Menu_Right)
        self.root.config(menu=menu)

        # 加载数据
        self.initDataMQ()
        # 自动化操作
        cwin = childWin.ChildWin(self.root, self.info_text, self.cllientId.get(), self.pwd.get())
        tk.Button(self.root, text='操作自动化', bg='#B5BC8C', width=11, height=1,
                  command=cwin.auto_win).place(x=20, y=400)
        tk.Button(self.root, text='模拟设备制造', bg='#E8D1A5', width=11, height=1,
                  command=self.mk_dev).place(x=120, y=400)
        self.root.mainloop()

    def mk_dev(self):
        #result = dataApi.make_device()
        #a, res = dataApi.checkResult(result)
        confirm = messagebox.askquestion('确认', '是否——生成新的网关设备')
        if confirm == 'yes':
            result = dataApi.make_device()
            a, res = dataApi.checkResult(result)
            if a == 1:
                self.info_text.tag_config('tag_2', foreground='green')
                self.info_text.insert(tk.END, str(res) + " \n")
                self.info_text.insert(tk.END,  " 复制 qcode 在iot平台扫描添加网关 \n", 'tag_2')
        else:
            pass

    def clearMsg(self):
        self.input_text.replace('1.0', 'end', '')
        self.info_text.replace('1.0', 'end', '')

    def build_submit(self):
        s_type = self.box_se.get()
        s_text = self.build_text.get()
        if s_text != '':
            if cves.index(s_type) == 0:
                self.info_text.insert(tk.END, dataApi.md5(s_text) + " \n")
            elif cves.index(s_type) == 1:
                self.info_text.insert(tk.END, dataApi.url_enc(s_text) + " \n")
            elif cves.index(s_type) == 2:
                self.info_text.insert(tk.END, dataApi.url_dec(s_text) + " \n")
            elif cves.index(s_type) == 3:
                self.info_text.insert(tk.END, dataApi.getEncode(s_text, 1) + " \n")
            elif cves.index(s_type) == 4:
                self.info_text.insert(tk.END, dataApi.getEncode(s_text, 2) + " \n")
            elif cves.index(s_type) == 5:
                self.clearMsg()
                self.info_text.insert(tk.END, dataApi.formatJson(s_text) + " \n")
        else:
            tk.messagebox.showinfo(title='data config', message='数据为空！~')

    def sendMsg(self):
        text_content = (self.input_text.get("0.0", "end").replace(" ", ""))
        # print(text_content)
        self.info_text.insert(tk.END, "发送消息： " + ": " + text_content + " \n")
        self.on_publish("v1/gateway/telemetry", text_content, 0)
        self.input_text.replace('1.0', 'end', '')

    def disCon(self):
        try:
            self.client.disconnect()
            self.isConnect = 0
            self.info_text.insert(tk.END, dataApi.getTimeStr() + " mqtt 断开连接 \n")
        except Exception as e:
            print(e)
        finally:
            print("final")
            self.client.loop_stop(force=True)


    def mqttCon(self):
        if self.isConnect == 1:
            tk.messagebox.showinfo(title='mqtt connection success', message='已经连接成功!')
            return
        self.client = mqtt.Client(self.cllientId.get(),clean_session=True, transport='tcp')
        try:
            userName = self.userName.get();
            pwd = self.pwd.get()
            self.client.username_pw_set(userName, pwd)
            self.client.connect(self.url.get(), int(self.port.get()), 60)
            self.client.on_connect = self.on_connect  # 返回连接状态的回调函数
            self.on_subscribe()
            self.client.loop_start()  # 以start方式运行，需要启动一个守护线程，让服务端运行，否则会随主线程死亡
            #self.client.loop_forever()  # 以forever方式阻塞运行。
            # self.on_publish("v1/gateway/telemetry", '{"A005F-230403102593799032_1":[{"dimcurve":19}]}', 0)
        except Exception as e:
            # print(e)
            tk.messagebox.showinfo(title='mqtt connection', message='mqtt 连接失败')

    def initDataMQ(self):
        data = dataApi.readConfig()
        self.url.insert(0, data["host"])
        self.port.insert(0, data["port"])
        self.userName.insert(0, data["username"])
        self.pwd.insert(0, data["password"])
        self.cllientId.insert(0, data["clientid"])

    # subscribe 消息
    def on_subscribe(self):
        self.client.subscribe("v1/devices/me/rpc/request/+", 0)
        self.client.on_message = self.on_message_come  # 消息到来处理函数

    # 消息处理函数
    def on_message_come(self, client, userdata, msg):
        # 设置文本格式tag
        self.info_text.tag_config('tag_1', foreground='red')
        # return str(msg.payload.decode('utf-8')) "INFO:str_trans_to_md5 success"  "INFO:"+str(msg.payload.decode('utf-8'))
        self.info_text.insert(tk.END,
                              "接收消息: " + msg.topic + " " + ": " + str(msg.payload.decode('utf-8') + " \n"), 'tag_1')

    # publish 消息
    def on_publish(self, topic, payload, qos):
        #发布消息时把retain设置为false
        self.client.publish(topic, payload, qos,False)

    def Exit(self):
        Exit = messagebox.askokcancel('退出', '确定退出吗?')
        if Exit == True:
            self.root.destroy()
        sys.exit()

    def Iot(self):
        webbrowser.open('http://192.168.6.43/')

    def IotAPi(self):
        webbrowser.open('http://192.168.6.43:8080/swagger-ui/')

    def software_info(self):
        messagebox.showinfo("软件信息", "write by laich \nhttps://gitee.com/laich/pymqtt-client")

    # def git_hub(self):
    #     webbrowser.open('https://gitee.com/laich/pymqtt-client')

    # 连接MQTT服务器
    def on_connect(self, client, userdata, flags, rc):
        """一旦连接成功, 回调此方法"""
        rc_status = ["连接成功", "协议版本错误", "无效的客户端标识", "服务器无法使用", "用户名或密码错误", "无授权"]
        if self.isConnect == 1:
            return  # 不需要重连
        if rc == 0:
            self.isConnect = 1
            #tk.messagebox.showinfo(title='mqtt connection', message='Welcome, mqtt successfully 连接成功')
            self.info_text.insert(tk.END, dataApi.getTimeStr() + " mqtt 连接成功 \n")
            dict_ = {}
            dict_["host"] = self.url.get()
            dict_["port"] = self.port.get()
            dict_["userName"] = self.userName.get()
            dict_["password"] = self.pwd.get()
            dict_["clientId"] = self.cllientId.get()
            dataApi.writeConfig(dict_)
        else:
            tk.messagebox.showinfo(title='mqtt config', message='lose, 连接失败:' + rc_status[rc])
            client.disconnect()


class API_from:
    def __init__(self):
        self.root = tk.Tk()
        # get main window position
        root_x = self.root.winfo_rootx()
        root_y = self.root.winfo_rooty()
        # add offset
        win_x = root_x + 300
        win_y = root_y + 100
        self.root.title("新建窗口干嘛用")
        self.root.geometry(f'+{win_x}+{win_y}')
        tk.Label(self.root, text='根据图标：icon_hash="110"').place(x=40, y=10)
        tk.Label(self.root, text='网页内容识别：body="xxx"').place(x=10, y=40)
        self.root.resizable(0, 0)


if __name__ == '__main__':
    RootFrom()
    # if is_admin():
    #     print("1")
    #     start = RootFrom()
    # else:
    #     print(2)#Shell32库是Windows操作系统中的一个动态链接库，它提供了许多与文件和系统操作相关的函数。在Python中，我们可以使用ctypes模块来调用Shell32库中的函数。
    #     ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, __file__, None, 1)
